﻿using System;
using System.IO;
using System.Text;
using System.Web.UI;
using CKEditor.NET;
using ReadyApps.Common;
using ReadyApps.Data;
using ReadyApps.Wiki.Templates;

namespace ReadyApps.Wiki.Views
{
    class WikiEditContentView : WikiContentViewBase
    {
        #region Variables and Constants

        private const string EDITOR_CONTROL_ID = "editorControl";

        private WikiControlSettings controlSettings;
        private string baseFolder;
        private CKEditorControl editor;

        #endregion

        #region Events

        private event EventHandler cancelButtonClick;
        public event EventHandler CancelButtonClick
        {
            add { cancelButtonClick += value; }
            remove { cancelButtonClick -= value; }
        }

        private event EventHandler<SavePageEventArgs> saveButtonClick;
        public event EventHandler<SavePageEventArgs> SaveButtonClick
        {
            add { saveButtonClick += value; }
            remove { saveButtonClick -= value; }
        }

        #endregion

        #region Constructor

        public WikiEditContentView(int wikiPageID, IWikiDataProvider wikiDataProvider, IWikiUrlManager wikiUrlManager,
            WikiControlSettings wikiControlSettings, string requestBaseFolder)
            : base(wikiPageID, wikiDataProvider, wikiUrlManager)
        {
            if (wikiControlSettings == null)
            {
                throw new ArgumentNullException("wikiControlSettings");
            }
            controlSettings = wikiControlSettings;
            baseFolder = requestBaseFolder;
        }

        #endregion

        #region Public Methods

        public override void BuildControlTree(ControlCollection controls, bool raiseEvents)
        {
            Control container = new Control();

            // Instantiate the template
            ITemplate layoutTemplate = controlSettings.EditLayoutTemplate ?? new WikiDefaultEditLayoutTemplate();
            layoutTemplate.InstantiateIn(container);

            // Locate the content and wiki controls control
            Control contentControl = WebUtilities.FindControlRecursive(container, WikiController.CONTENT_CONTROL_ID);
            if (contentControl == null)
            {
                throw new Exception(string.Format("A server control with an ID of '{0}' was not found in the display template.", WikiController.CONTENT_CONTROL_ID));
            }
            Control controlsControl = WebUtilities.FindControlRecursive(container, WikiController.CONTROLS_CONTROL_ID);
            if (controlsControl == null)
            {
                throw new Exception(string.Format("A server control with an ID of '{0}' was not found in the display template.", WikiController.CONTROLS_CONTROL_ID));
            }

            editor = new CKEditorControl();
            editor.ID = EDITOR_CONTROL_ID;

            string basePath;
            if (!string.IsNullOrEmpty(controlSettings.CKEditorBasePath))
            {
                basePath = controlSettings.CKEditorBasePath;
            }
            else if (!string.IsNullOrEmpty(ReadyAppsSettings.CKEditorBasePath))
            {
                basePath = ReadyAppsSettings.CKEditorBasePath;
            }
            else
            {
                basePath = string.Empty;
            }
            editor.BasePath = basePath;

            editor.config.extraPlugins = "autogrow,managedlink";
            editor.config.toolbar = new object[] {
                new object[] { "Source", "-", "Save", "NewPage", "DocProps", "Preview", "-", "Templates" },
                new object[] { "Cut", "Copy", "Paste", "PasteText", "PasteFromWord", "-", "Undo", "Redo" },
                new object[] { "Find", "Replace", "-", "SelectAll", "-", "SpellChecker", "Scayt" },
                "/",
                new object[] { "Bold", "Italic", "Underline", "Strike", "Subscript", "Superscript", "-", "RemoveFormat" },
                new object[] { "NumberedList", "BulletedList", "-", "Outdent", "Indent", "-", "Blockquote", "CreateDiv",
                "-", "JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock" },
                new object[] { "Link", "ManagedLink", "Unlink", "Anchor" },
                new object[] { "Image", "Table", "HorizontalRule", "SpecialChar", "PageBreak" },
                "/",
                new object[] { "Styles", "Format", "Font", "FontSize" },
                new object[] { "TextColor", "BGColor" },
                new object[] { "Maximize", "ShowBlocks", "-", "About" }
            };
            editor.Text = GetEditableText();

            if (raiseEvents)
            {
                controlSettings.OnIncludeResource(this, new IncludeResourceEventArgs(IncludeType.Stylesheet, WikiController.MANAGED_LINK_CSS_FILE));
                controlSettings.OnIncludeResource(this, new IncludeResourceEventArgs(IncludeType.ScriptFile, WikiController.CKEDITOR_URL_REDIRECT_FILE));
                controlSettings.OnIncludeResource(this, new IncludeResourceEventArgs(IncludeType.ScriptBlock, GetAvailablePageLinksJSVariable()));
            }

            contentControl.Controls.Add(editor);

            WikiControlButton cancelEditPageButton = WikiControlButton.GetFromTemplate(controlSettings.ButtonTemplate);
            cancelEditPageButton.ButtonControl.Text = "Cancel";
            cancelEditPageButton.ButtonControl.Click += cancelButtonClick;
            controlsControl.Controls.Add(cancelEditPageButton.RootControl);

            WikiControlButton saveEditPageButton = WikiControlButton.GetFromTemplate(controlSettings.ButtonTemplate);
            saveEditPageButton.ButtonControl.Text = "Save";
            saveEditPageButton.ButtonControl.Click += new EventHandler(saveEditPageButton_Click);
            controlsControl.Controls.Add(saveEditPageButton.RootControl);

            controls.Clear();
            controls.Add(container);
        }

        #endregion

        #region Private Methods

        private void saveEditPageButton_Click(object sender, EventArgs e)
        {
            if (saveButtonClick != null)
            {
                saveButtonClick(this, new SavePageEventArgs(editor.Text));
            }
        }

        /// <summary>
        /// Gets the text that is editable in conformance with CKEditor and the custom CKEditor
        /// plug-in.
        /// </summary>
        /// <returns>A string of HTML text to be used by CKEditor for editing the content.</returns>
        private string GetEditableText()
        {
            Control hostControl = new Control();

            GetContentControls(hostControl, true);

            StringBuilder sb = new StringBuilder();
            hostControl.RenderControl(new HtmlTextWriter(new StringWriter(sb)));

            return sb.ToString();
        }
        
        /// <summary>
        /// Generates a string of JavaScript code that represents the available pages that can be
        /// linked to from the current page.
        /// </summary>
        /// <returns>A string of JavaScript code used by the CKEditor plug-in.</returns>
        private string GetAvailablePageLinksJSVariable()
        {
            StringBuilder builder = new StringBuilder("var pageLinkKeys =\n[");
            foreach (var link in dataProvider.GetAvailablePageLinks(pageID, baseFolder))
            {
                builder.Append("\n\t['");
                builder.Append(link.PageTitle);
                builder.Append("', '");
                builder.Append(link.PageID);
                builder.Append("'],");
            }
            builder.Remove(builder.Length - 1, 1);
            builder.Append("\n];\n");
            return builder.ToString();
        }

        #endregion
    }
}
